﻿using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Main : MonoBehaviour
{
    //fe
   //ahsjqe
    //五个预制体对应的5个效果
    public GameObject[] effects;
    //水果预制数组
    public GameObject[] prefabs;
    //记录运行中，水果实例的二维数组
    public GameObject[,] objects;
    //记录行
    public int Column;
    //记录列
    //wdw
    public int Row;
    //记录分数
    public int Score;
    public Text text;
    //s声明框
    public Transform Bored;

    public float Size = 1;
    public float startTime = 1;
    //创建一个缓存
    List<GameObject> cache = new List<GameObject>();
    // Start is called before the first frame update
    void Start()
    {
        //初始化二维数组的缓存
        objects = new GameObject[Column, Row];
        //随机数最大值
        int max = prefabs.Length;
        float sx = Column * -0.5f * Size + Size * 0.5f;
        float sy = Row * -0.5f * Size + Size * 0.5f;
        for (int i = 0; i < Column; i++)
        {

            for (int j = 0; j < Row; j++)
            {
                //生成一个随机数，索引预制体对象
                int index = Random.Range(0, max);
                //实例化水果对象
                GameObject go = GameObject.Instantiate(prefabs[index]);
                //实例化后，要把水果设置到当前脚本下
                go.transform.SetParent(transform);
                //设置对象当前的位置
                go.transform.localPosition = new Vector3(i * Size + sx, j * Size + sy, 0);
                go.transform.localScale = new Vector3(Size, Size, Size);
                //添加标签
                Mark mark = go.AddComponent<Mark>();
                //记录标签的信息
                mark.Column = i;
                mark.Row = j;
                //预制类型
                mark.index = index;
                //给一个名称
                go.name = index.ToString();
                //初始化一个碰撞对象
                go.AddComponent<BoxCollider2D>();
                //行更列保存在二维数组里面
                objects[i, j] = go;
            }
        }
    }

    /// <summary>
    /// 鼠标点击
    /// </summary>
    // Update is called once per frame
    void Update()
    {
        if (startTime > 0)
        {
            startTime -= Time.deltaTime;
        }
        if (startTime < 0)
        {
            //检测鼠标的左键。0是左键
            if (Input.GetMouseButtonDown(0))
            {
                //由主摄像机去做转换
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);/////
                //放松射线
                RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);
                //如果击中目标是有信息的，如果不是空的就继续下一步操作
                if (hit.transform != null)
                {
                    Bored.gameObject.SetActive(true);
                    Bored.position = hit.transform.position;

                    lastCol = curCol;
                    lastRow = curRow;
                    //击中哪一个目标，所有要得到标签
                    Mark mark = hit.transform.GetComponent<Mark>();
                    //当点击对象没有成功的话，我们要选择行于列
                    curCol = mark.Column;
                    curRow = mark.Row;
                    
                    cache.Clear();
                    //检测他的名称，传入mark的列和行
                    Check(hit.transform.gameObject.name, mark.Column, mark.Row);
                   
                    //如果里面的缓存大于等于三
                    if (cache.Count >= 3)
                    {
                      
                        //首次单击获得的分数，交换获得的分数
                        AddScore(cache.Count);

                        PalyDestory();
                    }
                    else
                    {
                        //进行交换测试
                        cache.Clear();
                        Swap();
                    }
                }
            }
        }
    }
    //检测行和列是否符合要求、、通过类型去判定
    void Check(string type, int column, int row)
    {
        //首先排除不符合要求的
        if (row < 0 || row >= Row || column < 0 || column >= Column)
            return;
        //获取当前缓存的目标
        GameObject go = objects[column, row];
        //判断是不是同一个类型，类型不相等返回去
        if (go.name != type)
            return;
        //防止重复添加
        if (cache.Contains(go))
            return;
        //如果符合要求，添加到缓存里面来
        cache.Add(go);
        //寻找上下左右，递归一下
        Check(type, column, row - 1);
        Check(type, column, row + 1);
        Check(type, column - 1, row);
        Check(type, column + 1, row);
    }
    //销毁的函数
    void PalyDestory()
    {
        //起始位置
        float sx = Column * -0.5f * Size + Size * 0.5f;
        float sy = Row * -0.5f * Size + Size * 0.5f;
        for (int i = 0; i < cache.Count; i++)
        {
            //清空他的记录。查询到哪一行哪一列
            Mark mark = cache[i].GetComponent<Mark>();
            //销毁二维数组里面的对象
            objects[mark.Column, mark.Row] = null;
            //初始化精灵
            GameObject go = GameObject.Instantiate(effects[mark.index]);
            go.transform.SetParent(transform);
            go.transform.position = new Vector3(mark.Column * Size + sx, mark.Row * Size+sy,0);
            go.transform.localScale = new Vector3(Size, Size, Size);
            GameObject.Destroy(cache[i]);
        }
        StartCoroutine(Wait(0.6f,Fall));
        
    }
    /// <summary>
    /// 播放精灵动画的时候才掉落、协程
    /// </summary>
    /// <param name="time"> 时间</param>
    /// <param name="action">时间过后的一个函数</param>
    /// <returns></returns>
    IEnumerator Wait(float time,System.Action action)
    {
        yield return new WaitForSeconds(time);
        action();
    }
    /// <summary>
    /// 让上面的物体往下掉落
    /// </summary>
    void Fall()
    {
        //起始位置
        float sx = Column * -0.5f * Size + Size * 0.5f;
        float sy = Row * -0.5f * Size + Size * 0.5f;
        //for循环去做循环检测
        for (int i = 0; i < Column; i++)
        {
            //统计每一列销毁了多少，
            int count = 0;
            for (int j = 0; j < Row; j++)
            {
                //二维数组对象是否为空
                if (objects[i, j] == null)
                {
                    count++;
                }
                else
                {
                    if (count > 0)
                    {

                        Mark m = objects[i, j].GetComponent<Mark>();
                        //计算他掉落多少行
                        int row = j - count;
                        m.Row = row;
                        //更新一下记录位置
                        objects[i, row] = objects[i, j];
                        //计算当前位置,移动当前组件,播放速度为0.3秒
                        objects[i, row].transform.DOMove(new Vector3(i * Size + sx, row * Size + sy, 0), 0.3f);
                        //将当前位置的物体置空
                        objects[i, j] = null;
                    }
                }
            }
        }
        Add();
    }
    /// <summary>
    /// 掉落之后添加物体
    /// </summary>
    void Add()
    {
        float sx = Column * -0.5f * Size + Size * 0.5f;
        float sy = Row * -0.5f * Size + Size * 0.5f;
        for (int i = 0; i < Column; i++)
        {
            for (int j = 0; j < Row; j++)
            {
                //缓存对象是否为空,如果为空
                if (objects[i, j] == null)
                {
                    int max = prefabs.Length;
                    int index = Random.Range(0, max);
                    //实例化水果对象
                    GameObject go = GameObject.Instantiate(prefabs[index]);
                    //实例化后，要把水果设置到当前脚本下
                    go.transform.SetParent(transform);
                    //设置对象当前的位置
                    go.transform.localPosition = new Vector3(i * Size + sx, (Row + 1) * Size + sy, 0);
                    go.transform.DOMove(new Vector3(i * Size + sx, j * Size + sy, 0), 0.3f);
                    go.transform.localScale = new Vector3(Size, Size, Size);
                    //添加标签
                    Mark mark = go.AddComponent<Mark>();
                    //记录标签的信息
                    mark.Column = i;
                    mark.Row = j;
                    //预制类型
                    mark.index = index;
                    //给一个名称
                    go.name = index.ToString();
                    //初始化一个碰撞对象
                    go.AddComponent<BoxCollider2D>();
                    //行更列保存在二维数组里面
                    objects[i, j] = go;
                }
            }
        }
    }
    //当前选中的行于列，与上一针选择的行于列
    int curCol, curRow;
    int lastCol, lastRow;
    /// <summary>
    /// 交换函数
    /// </summary>
    void Swap()
    {
        //计算他们的相对位置
        int ox = curCol - lastCol;
        int oy = curRow - lastRow;
        if (oy == 0)
        {
            if (ox == 1 || ox == -1)
            {
                SwapTest();
            }
        }
        else if (ox == 0)
        {
            if (oy==1|oy==-1)
            {
                SwapTest();
            }
        }
    }
    /// <summary>
    /// 如果符合交换条件，就交换
    /// </summary>
    void SwapTest()
    {
        //声明一个状态，默认是失败
        bool fail = true;
        GameObject a = objects[curCol, curRow];
        GameObject b = objects[lastCol, lastRow];
        objects[curCol, curRow] = b;
        objects[lastCol, lastRow] = a;
        //标签信息
        var mb = b.GetComponent<Mark>();
        mb.Column = curCol;
        mb.Row = curRow;

        var ma = a.GetComponent<Mark>();
        ma.Column = lastCol;
        mb.Row = lastRow;
        //局部选择当前行于列，为防止用户再一次点击，造成的记录改不
        int cc = curCol;
        int cr = curRow;
        int lc = lastCol;
        int lr = lastRow;
        //交换位置
        a.transform.DOMove(b.transform.position, 0.3f);
        b.transform.DOMove(a.transform.position, 0.3f).onComplete = () => {
            cache.Clear();//清理一下检测缓存
            Check(b.name, cc, cr);
            //交换两个类型，统计起来
            int c = 0;
            if (cache.Count >= 3)
            {
                c += cache.Count;
                fail = false;
                PalyDestory();
            }
            cache.Clear();
            Check(a.name, lc, lr);
            if (cache.Count >= 3)
            {
                c += cache.Count;
                fail = false;
                PalyDestory();
            }
            cache.Clear();
            AddScore(c);
            if (fail)
            {
                objects[cc, cr] = a;
                objects[lc, lr] = b;
                a.transform.DOMove(b.transform.position, 0.3f);
                b.transform.DOMove(a.transform.position, 0.3f);
                ma.Column = cc;
                ma.Row = cr;
                mb.Column = lc;
                mb.Row = lr;
            }
        }; ///////////////////////////////////////////
        
          
        

    }/// <summary>
    /// 用一个函数去添加分数
    /// </summary>
    /// <param name="count"></param>
    void AddScore(int count)
    {
        if (count < 3)
        
            return;
            //先给他一个基础分
            Score += count * 100;
            //减去最基本的三个,最少要求
            count -= 3;
            //附加分
            Score += count * count * 10;
            //转换成文本显示出来
            text.text = Score.ToString();
        
    }
}
